package com.logistics.map.service;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.logistics.config.service.ConfigService;
import com.logistics.log.entity.domain.Log;
import com.logistics.map.entity.domain.Map;
import com.logistics.map.entity.domain.MapComponents;
import com.logistics.map.entity.domain.MapRoute;
import com.logistics.map.entity.domain.MapRouteEdges;
import com.logistics.map.entity.model.*;
import com.logistics.map.mapper.MapMapper;
import com.logistics.rcs.entity.model.RcsCoordinateRow;
import com.logistics.rcs.service.RcsService;
import com.logistics.utils.aspect.annotation.Insert;
import com.logistics.utils.aspect.annotation.Pager;
import com.logistics.utils.bean.ResultPager;
import com.logistics.utils.constants.Constants;
import com.logistics.utils.constants.Message;
import com.logistics.utils.exception.MessageException;
import com.logistics.utils.message.Manager;
import com.logistics.utils.security.EncryptionUtils;
import com.logistics.utils.tool.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class MapService extends ServiceImpl<MapMapper, Map> {

    @Autowired
    private MapComponentsService mapComponentsService;

    @Autowired
    private MapRouteNodesService mapRouteNodesService;

    @Autowired
    private MapRouteEdgesService mapRouteEdgesService;

    @Autowired
    private MapRouteService mapRouteService;

    @Autowired
    private ConfigService configService;

    @Autowired
    private RcsService rcsService;

    /**
     * 分页查询地图列表
     * @param param
     * @return
     */
    @Pager
    public ResultPager pager(MapPager param){
        IPage page = new Page(param.getCurrent(), param.getPageSize());
        QueryWrapper<Map> queryWrapper = new QueryWrapper();
        queryWrapper.lambda().like(StringUtils.isNotNull(param.getName()), Map::getName, param.getName());
        queryWrapper.lambda().eq(StringUtils.isNotNull(param.getType()), Map::getType, param.getType());
        queryWrapper.lambda().ge(StringUtils.isNotNull(param.getBeginDate()),
                Map::getCreateTime,
                param.getBeginDate())
                .le(StringUtils.isNotNull(param.getEndDate()),
                        Map::getCreateTime,
                        param.getEndDate());
        IPage<Map> result = this.page(page, queryWrapper.lambda().orderByDesc(Map::getCreateTime));
        return new ResultPager(result.getRecords().stream()
                .map(MapRow::build).collect(Collectors.toList()), (int) result.getTotal());
    }

    /**
     * 查询详细
     * @param id
     * @return
     * @throws MessageException
     */
    public MapRow details(String id) throws MessageException {
        if(StringUtils.isNull(id)){
            throw new MessageException(Manager.getMessage(Message.MSG1005.getCode()));
        }
        MapRow result = MapRow.build(this.getOne(new LambdaQueryWrapper<Map>().eq(Map::getId, id)));
        // 查询路线code码
        List<String> codes = mapRouteService.routeCodeByMapId(id);

        //
        java.util.Map<String, String> configMaps = configService.valuesByType(Arrays.asList(Constants.CONFIG_MAP_WIDTH, Constants.CONFIG_MAP_HEIGHT,
                Constants.CONFIG_MAP_X, Constants.CONFIG_MAP_Y, Constants.CONFIG_MAP_PROPORTION));
        java.util.Map<String, RcsCoordinateRow> coordinateRows = rcsService.allCoordinateRows();
        List<MapComponentsRow> componentsRows = mapComponentsService.byMapId(id);
        // 需要修改x轴y轴的数据
        List<MapComponentsRow> updates = componentsRows.stream().filter(item -> {
            // 计算x轴偏移量
            BigDecimal pointX = new BigDecimal(configMaps.get(Constants.CONFIG_MAP_X))
                    .divide(new BigDecimal(configMaps.get(Constants.CONFIG_MAP_PROPORTION)))
                    .subtract(new BigDecimal(configMaps.get(Constants.CONFIG_MAP_WIDTH)).divide(new BigDecimal("2")));
            // 计算y轴偏移量
            BigDecimal pointY = new BigDecimal(configMaps.get(Constants.CONFIG_MAP_HEIGHT)).divide(new BigDecimal("2"))
                    .subtract(new BigDecimal(configMaps.get(Constants.CONFIG_MAP_Y))
                            .divide(new BigDecimal(configMaps.get(Constants.CONFIG_MAP_PROPORTION))));
            // 点位坐标 单位米
            if(StringUtils.isNotNull(item.getLocation())){
                RcsCoordinateRow coordinateRow = coordinateRows.get(item.getLocation().split("-")[1]);
                if(StringUtils.isNotNull(coordinateRow)){
                    BigDecimal x = coordinateRow.getX().divide(new BigDecimal(configMaps.get(Constants.CONFIG_MAP_PROPORTION)));
                    BigDecimal y = coordinateRow.getY().divide(new BigDecimal(configMaps.get(Constants.CONFIG_MAP_PROPORTION)));
                    BigDecimal lastX= x.add(pointX).setScale(0, BigDecimal.ROUND_UP);
                    BigDecimal lastY = pointY.subtract(y).setScale(0, BigDecimal.ROUND_UP);
                    if(StringUtils.isNull(item.getX()) && StringUtils.isNull(item.getY())){
                        item.setX(String.valueOf(lastX));
                        item.setY(String.valueOf(lastY));
                        return true;
                    }else if(new BigDecimal(item.getX()).subtract(lastX).compareTo(new BigDecimal(20)) >= 0
                            || new BigDecimal(item.getX()).subtract(lastX).compareTo(new BigDecimal(-20)) <= 0
                            || new BigDecimal(item.getY()).subtract(lastY).compareTo(new BigDecimal(20)) >= 0
                            || new BigDecimal(item.getY()).subtract(lastY).compareTo(new BigDecimal(-20)) <= 0
                    ){
                        item.setX(String.valueOf(lastX));
                        item.setY(String.valueOf(lastY));
                        return true;
                    }
                }
            }
            return false;
        }).collect(Collectors.toList());
        // 更新点位
        if(!updates.isEmpty()){
            List<MapComponents> ups = updates.stream().map(item -> MapComponents.
                    build(new BigDecimal(item.getX()), new BigDecimal(item.getY()) , item.getId())).collect(Collectors.toList());
            mapComponentsService.updateBatchById(ups);
        }
//        if(!componentsRows.isEmpty()){
//            // 查询路线点
//            List<MapComponentsRow> nodesRows = mapRouteNodesService.listByCode(codes);
//            componentsRows.addAll(nodesRows);
//            result.setEdges(mapRouteEdgesService.listByCode(codes));
//        }
        result.setNodes(componentsRows);
        return result;
    }

    /**
     * 保存
     * @param save
     */
    @Insert
    @Transactional
    public java.util.Map save(MapSave save) throws MessageException {
        Integer mapId;
        if(StringUtils.isNull(save.getId())){
            Map map = Map.build(save);
            this.save(map);
            mapId = map.getId();
        }else{
            mapId = Integer.parseInt(save.getId());
            this.update(Map.build(save), new LambdaQueryWrapper<Map>().eq(Map::getId, save.getId()));
//            mapComponentsService.removeByMapId(save.getId());
//            List<String> codes = mapRouteService.routeCodeByMapId(mapId.toString());
//            if(codes.size() > 0){
//                mapRouteNodesService.deleteByRouteCode(codes);
//                mapRouteEdgesService.deleteByRouteCode(codes);
//                save.getRouteNods().stream().forEach(e -> mapRouteNodesService.save(e));
//                save.getEdges().stream().forEach(e -> mapRouteEdgesService.save(e));
//            }
        }
        List<MapComponentsRow> componentsRows = mapComponentsService.byMapId(mapId.toString());
        List<String> uuids = componentsRows.stream().map(MapComponentsRow::getUuid).collect(Collectors.toList());
        // 需要添加的节点
        List<MapComponentsSave> insertNodes = save.getNodes().stream().filter(e -> !uuids.contains(e.getUuid())).
                collect(Collectors.toList());
        List<String> nodeUuid = save.getNodes().stream().map(MapComponentsSave::getUuid).collect(Collectors.toList());
        // 需要删除的节点
        List<Integer> deleteIds = componentsRows.stream().filter(e -> !nodeUuid.contains(e.getUuid()))
                .map(MapComponentsRow::getId).collect(Collectors.toList());
        // 转换成map
        java.util.Map<String, MapComponentsRow> rowMaps = componentsRows.stream().
                collect(Collectors.toMap(MapComponentsRow::getUuid, item -> item));
        // 修改的数据
        List<MapComponentsSave> updates = save.getNodes().stream().filter(item ->
                                StringUtils.isNotNull(rowMaps.get(item.getUuid())) &&
                !StringUtils.isEquals(EncryptionUtils.md5Encode(JSONObject.toJSONString(MapComponentCompare.build(item))),
                        EncryptionUtils.md5Encode(JSONObject.toJSONString(MapComponentCompare.build(rowMaps.get(item.getUuid())))))).
                collect(Collectors.toList());
        // 添加节点
        if(!insertNodes.isEmpty()){
            insertNodes.forEach(item ->  mapComponentsService.save(item));
        }
        // 删除节点
        if(!deleteIds.isEmpty()){
            mapComponentsService.remove(new LambdaQueryWrapper<MapComponents>().in(MapComponents::getId, deleteIds));
        }
        // 变更节点
        if(!updates.isEmpty()){
            updates.forEach(item -> {
                System.out.println(MapComponentCompare.build(rowMaps.get(item.getUuid())));
                System.out.println(MapComponentCompare.build(item));
                mapComponentsService.update(MapComponents.build(item),
                        new LambdaQueryWrapper<MapComponents>().eq(MapComponents::getUuid, item.getUuid()));
            });
        }
        java.util.Map map = new HashMap();
        map.put("id", mapId);
        return map;
    }

    /**
     * 删除地图
     * @param ids
     * @throws MessageException
     */
    @Transactional
    public void delete(String ids) throws MessageException {
        if(StringUtils.isNull(ids)){
            throw new MessageException(Manager.getMessage(Message.MSG1005.getCode()));
        }
        this.remove(new LambdaQueryWrapper<Map>().in(Map::getId, StringUtils.splitToList(ids, ",")));
        mapComponentsService.removeByMapId(ids);
    }
}
